#include "DmxSetter.h"

#include <QDebug>

#include "ofxGenericDmx.h" /* DMX Interface code */
//#include "ParallelPort.h"

#include "SwitchWatcher.h"


DmxSetter::DmxSetter(QObject *parent)
	: QObject(parent)
	, m_isSwitchOn(false)
	, m_isSwitchMaster(true)
	, m_dmxInterface(0)
	, m_enableAltProfile(true)
	, m_altSwitchTriggerTime(2500)
	, m_switchWatcher(new SwitchWatcher())
{
	connect(m_switchWatcher, SIGNAL(switchToggled(bool)), this, SLOT(switchToggled(bool)));
	
	// Initialize all channels to 0 until told otherwise
	m_channelStates.fill(0);
	
	// Setup the 'switch on' profile - the DMX values to use when the the switch is
	// master (m_isSwitchMaster) and the switch is toggled on.
	// NOTE: sendDmx() will ensure that [0] is 0
	m_switchOnProfile.fill(255);
	
	// alt profile
	m_switchOnAltProfile.fill(0);
	m_switchOnAltProfile[5] = 255; // the 'cross' channel at PHC - I think. TODO: confirm next time at PHC
		
	if(!initDmx())
		qDebug() << "Error connecting to DMX output device, the program will not function as intended.";
}

DmxSetter::~DmxSetter()
{
	closeDmx();
	
	if(m_dmxInterface)
	{
		delete m_dmxInterface;
		m_dmxInterface = 0;
	}
		
	if(m_switchWatcher)
	{
		delete m_switchWatcher;
		m_switchWatcher = 0;
	}
}

void DmxSetter::setSwitchMaster(bool flag)
{
	qDebug() << "DmxSetter::setSwitchMaster: "<<flag; 
	m_isSwitchMaster = flag;
	
	if(flag)
	{
		// Store current values of channel states
		m_channelStates_beforeSwitchMaster = m_channelStates;
		
		// Send out the correct on or off profile
		switchToggled(m_isSwitchOn);
	}
	else
	{
		// Restore previous channel states
		m_channelStates = m_channelStates_beforeSwitchMaster;
		sendDmx(m_channelStates);
	}
}

void DmxSetter::setDmxChannel(int chan, int val)
{
	DmxValueList values = m_channelStates;
	values[chan] = val;
	setDmxChannels(values);
}

void DmxSetter::setDmxChannels(DmxValueList values)
{
	if(m_isSwitchMaster)
	{
		// Disregard input
		// TODO: Output error?
		qDebug() << "DmxSetter::setDmxChannels: switch is master, not setting data";
	}
	else
	{
		sendDmx(values);
	}
}

void DmxSetter::setSwitchOnProfile(DmxValueList values)
{
	m_switchOnProfile = values;
	
	// Immediately update the DMX output with new values
	if(m_isSwitchMaster && m_isSwitchOn)
		switchToggled(m_isSwitchOn);
}

void DmxSetter::switchToggled(bool flag)
{
	qDebug() << "DmxSetter::switchToggled: "<<flag;
	m_isSwitchOn = flag;
	
	// Set the m_switchOnProfile if switch on, 0 if off
	if(flag)
	{
		// Send out the 'switch on' profile
		
		bool altTriggered = false;
		if(m_enableAltProfile)
		{
			if(m_lastSwitchOnTime.elapsed() < m_altSwitchTriggerTime)
			{
				m_channelStates = m_switchOnAltProfile;
				altTriggered = true;
				qDebug() << "DmxSetter::switchToggled: Triggered alternate 'on' profile with a toggle time of "<<m_lastSwitchOnTime.elapsed()<<"ms, which is inside the required "<< m_altSwitchTriggerTime<<"ms";
			}
		}
		
		if(!altTriggered)
		{
			qDebug() << "DmxSetter::switchToggled: Regular 'on' profile";
			m_channelStates = m_switchOnProfile;
		}
			
		sendDmx(m_channelStates);
		
		m_lastSwitchOnTime.restart();
	}
	else
	{
		// Send all black since switch is off
		m_channelStates.fill(0);
		sendDmx(m_channelStates);
	}
}

void DmxSetter::sendDmx(DmxValueList values)
{
	// Update current channel states
	m_channelStates = values;
	
	//force first byte to zero (it is not a channel but DMX type info - start code)
	m_channelStates[0] = 0; 	
	
	// Do the send
	if (!m_dmxInterface || !m_dmxInterface->isOpen()) 
	{
		qDebug() << "DmxSetter::sendDmx: No ENTTEC device open, not sending DMX";
	}
	else
	{
		//qDebug() << "Writing value "<<value<<" to channel "<<num;
		
		// TODO: Will this really work?
		// E.g. the *..data(), or do we need to convert to something else
//		qDebug() << "DmxSetter::sendDmx: Received data";
		
		unsigned char *data = m_channelStates.data();
 		int x = (int)data[4]; 
 		//qDebug() << "DmxSetter: test at pos 4: " << x;
		
		m_dmxInterface->writeDmx(data, NUM_DMX_CHANNELS );
	}
}

bool DmxSetter::initDmx()
{
	m_channelStates.fill(255);
	m_channelStates_beforeSwitchMaster.fill(255);
	
	// m_switchOnProfile is setup in constructor
	
	//open the device
	m_dmxInterface = ofxGenericDmx::openFirstDevice();
	if ( m_dmxInterface == 0 )
	{
		qDebug() << "DmxSetter::initDmx: No ENTTEC PRO device found.";
		return false;
	}
	
	return true;
}

void DmxSetter::closeDmx()
{
	if(!m_dmxInterface)
		return;
		
	if(m_dmxInterface->isOpen())
		m_dmxInterface->close();
}

